package daliytool.service;

import daliytool.http.server.response.ResultObject;
import daliytool.http.server.support.WebContext;
import daliytool.vo.HistoryVO;
import daliytool.vo.TreeVO;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * 描述 新通教育
 *
 * @author ddshuai
 * @date 2018-10-26 09:24
 **/
public class FileService {

    private static final Logger logger = LoggerFactory.getLogger(FileService.class);


    private static Set<String> ignoreDir = new HashSet<>(10);
    private static Set<String> ignoreFile = new HashSet<>(10);
    private static Set<String> ignoreSuffix = new HashSet<>(10);
    private static final String JAVA_EXTENSION = ".java";
    private static final String CLASS_EXTENSION = ".class";

    static {
        ignoreDir.add("target");
        ignoreDir.add(".git");
        ignoreDir.add(".idea");

        ignoreFile.add(".mymetadata");
        ignoreFile.add(".project");

        ignoreSuffix.add(".iml");
    }

    public static ResultObject getRootPath() {
        return ResultObject.getInstance(WebContext.getRootPath());
    }

    /**
     * 获取项目树
     *
     * @param
     * @return
     */
    public static ResultObject<List<TreeVO>> getTree(String path, String sys) {
        logger.debug("获取文件列表：path:{},sys:{}",path,sys);
        if (Objects.equals("root", path)) {
            path = WebContext.getRootPath(sys);
            if (StringUtils.isEmpty(path)) {
                return ResultObject.generateError("please set root path");
            }
        }
        ResultObject<List<TreeVO>> resultObject;
        List<TreeVO> treeVOS = new ArrayList<>();

        try {
            File rootFile = new File(path);
            if (rootFile.isDirectory()) {
                File[] files = rootFile.listFiles();

                if (files != null) {
                    Arrays.sort(files, (a, b) -> Boolean.compare(b.isDirectory(), a.isDirectory()));
                    for (File file : files) {
                        if (needIgnore(file.getName(), file.isDirectory())) {
                            continue;
                        }
                        TreeVO treeVO = new TreeVO();
                        treeVO.setId(treeVO.hashCode());
                        treeVO.setWinPath(getPulishCodePath(file, "win"));
                        treeVO.setLinuxPath(getPulishCodePath(file, "linux"));
                        treeVO.setPath(file.getAbsolutePath());
                        treeVO.setIsLeaf(!file.isDirectory());
                        treeVO.setLabel(file.getName());
                        treeVOS.add(treeVO);
                    }
                }
            }

            resultObject = ResultObject.getInstance(treeVOS);
        } catch (Exception e) {
            logger.error("获取文件列表异常", e);
            resultObject = ResultObject.generateError("获取文件列表异常:" + e.getMessage());
        }

        return resultObject;
    }

    /**
     * 获取代码的发布路径
     *
     * @param file
     * @param type
     * @return 发布路径
     * 规则
     * 发布目录
     * web,src
     * <p>
     * resources下文件需要找飞哥
     * web.xml文件需要找飞哥，不能直接发
     */
    private static String getPulishCodePath(File file, String type) {
        String publishPath = "";
        String absolutePath = file.getAbsolutePath();
        /**
         * 如果是WEB-INF/classes下的文件直接去前缀
         */
        String webInfoClassesPath = "WEB-INF" + File.separator + "classes";
        String webDirPath = File.separator + "web" + File.separator;
        String srcDirPath = File.separator + "src" + File.separator;
        String resourcesDirPath = File.separator + "resources" + File.separator;

        String winSeparator = "\\";
        String linuxSeparator = "/";

        //如果是WEB-INFO/classes目录下的，则直接去掉前缀就好啦
        if (absolutePath.contains(webInfoClassesPath)) {
            String[] pathAry = absolutePath.split(webInfoClassesPath);
            if (pathAry.length == 2) {
                publishPath = webInfoClassesPath + pathAry[1];
            } else {
                publishPath = "不能选择根目录" + webInfoClassesPath + "发布";
            }

            //如果是配置文件，需要特殊处理 todo

        } else if (absolutePath.contains(srcDirPath)) {
            //需要去掉src前缀，拼上WEB-INFO/classes
            if (Objects.equals(winSeparator,File.separator)){
                srcDirPath = "\\\\src\\\\";
            }
            publishPath = webInfoClassesPath + File.separator + absolutePath.split(srcDirPath)[1];
            if (file.isFile()) {
                if (absolutePath.endsWith(JAVA_EXTENSION)) {
                    publishPath = publishPath.replace(JAVA_EXTENSION, CLASS_EXTENSION);
                }
            }
        } else if (absolutePath.contains(webDirPath)) {
            //这个目录下面都是前端文件，只需要去掉前缀就行
            if (Objects.equals(winSeparator,File.separator)){
                webDirPath = "\\\\web\\\\";
            }
            publishPath = absolutePath.split(webDirPath)[1];
        } else if (absolutePath.contains(resourcesDirPath)) {
            //配置文件一律不能直接发布，选择就给提示
            publishPath = file.getName() + "是配置类文件，不可直接发布，需与王才飞确认";
        } else {
            //不在发布的代码清单内容范围
            publishPath = file.getName() + "不在正常的发布清单文件目录范围【web,resources,src,WEB-INFO】";
        }

        if (Objects.equals("web.xml", file.getName()) || Objects.equals("Gemway.xml", file.getName())) {
            publishPath = file.getName() + "不能直接发布，需与王才飞确认";
        }

        boolean isLinux = Objects.equals(linuxSeparator, File.separator);

        //转成window路径
        if (Objects.equals("win", type) && isLinux) {
            publishPath = publishPath.replace(linuxSeparator, winSeparator);
        }

        //转成linux路径
        if (Objects.equals("linux", type) && !isLinux) {
            publishPath = publishPath.replace(winSeparator, linuxSeparator);
        }

        return publishPath;
    }

    private static boolean needIgnore(String fileName, boolean isDir) {
        if (isDir) {
            return ignoreDir.contains(fileName);
        } else {
            if (ignoreFile.contains(fileName)) {
                return true;
            }

            for (String suffix : ignoreSuffix) {
                if (fileName.endsWith(suffix)) {
                    return true;
                }
            }

        }

        return false;
    }

    public static ResultObject saveHistory(Map param) {
        logger.debug("保存代码清单：{}",param);
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");

        String winCodePath = param.get("winCodePath") == null ? "" : param.get("winCodePath").toString();
        String linuxCodePath = param.get("linuxCodePath") == null ? "" : param.get("linuxCodePath").toString();
        String sys = param.get("sys") == null ? "" : param.get("sys").toString();

        String date = simpleDateFormat.format(new Date());
        LinkedList<HistoryVO> historyVOS = loadHistory();
        if (StringUtils.isNotEmpty(winCodePath)){
            HistoryVO historyVO = new HistoryVO();
            historyVO.setCreateDate(date);
            historyVO.setWinCodePath(winCodePath);
            historyVO.setLinuxCodePath(linuxCodePath);
            historyVO.setSys(sys);
            historyVOS.add(historyVO);
        }

        writeToHistoryFile(historyVOS);
        logger.debug("保存代码清单：{}","成功");

        return ResultObject.getInstance();
    }

    private static void writeToHistoryFile(LinkedList<HistoryVO> historyVOS) {
          if (historyVOS != null){
              List<String> all = new ArrayList<>();
              for (HistoryVO historyVO : historyVOS) {
                  List<String> strings = Arrays.asList("#####",historyVO.getCreateDate(),historyVO.getWinCodePath(),historyVO.getLinuxCodePath(),historyVO.getSys() == null ? "" : historyVO.getSys().toUpperCase());
                  all.addAll(strings);
              }
              try {
                  FileUtils.writeLines(new File(System.getProperty("user.dir") + "/history/history.txt"),all);
              } catch (IOException e) {
                  logger.error("保存历史数据异常");
              }
          }
    }

    private static LinkedList<HistoryVO> loadHistory() {
        LinkedList<HistoryVO> linkedList = new LinkedList<>();
        File file = new File(System.getProperty("user.dir") + "/history/history.txt");
        if (!file.exists()) {
            return linkedList;
        }
        try {
            List<String> list = FileUtils.readLines(file, "utf-8");
            HistoryVO historyVO = null;
            int index = 0;
            for (String line : list) {
                if (line.startsWith("#####")) {
                    if (historyVO != null){
                        linkedList.add(historyVO);
                    }
                    historyVO = new HistoryVO();
                    index = 0;
                    continue;
                }
                buildHistoryVO(index, line, historyVO);
                index++;
            }
            linkedList.add(historyVO);
        } catch (Exception e) {
            logger.error("加载历史数据异常", e);
        }

        return linkedList;
    }

    private static void buildHistoryVO(int index, String line, HistoryVO historyVO) {
        if (index == 0) {
            historyVO.setCreateDate(line);
        } else if (index == 1) {
            historyVO.setWinCodePath(line);
        } else if (index == 2){
            historyVO.setLinuxCodePath(line);
        }else {
            historyVO.setSys(line);
        }
    }

    public static ResultObject<LinkedList<HistoryVO>> queryHistory(){
        LinkedList<HistoryVO> historyVOS = loadHistory();
        Collections.reverse(historyVOS);
        return ResultObject.getInstance(historyVOS);
    }

    public static void main(String[] args) {
        Map<String,String> map = new HashMap<>(5);
        map.put("winCodePath","ddshuai");
        map.put("linuxCodePath","eamonsi");
        saveHistory(map);
    }
}
